/*
* Copyright (c) 2007 by Kirill Kolodyazhniy.
* See the file "license.terms" for information on usage and redistribution.
*/

#include "dxvertexdeclaration.h"
#include "refptr.h"
#include "graphic.h"
#include "dxmappings.h"

#ifdef _DEBUG
#ifdef _MSC_VER
   #define new new( _CLIENT_BLOCK, __FILE__, __LINE__)
#endif
#endif // _DEBUG

namespace Engine
{
	/**********************************************************************************************************/
	DXVertexDeclaration::DXVertexDeclaration(DXRenderSystem* renderSystem)
		:m_renderSystem(renderSystem)
		,m_needUpdate(true)
	{
	}
	/**********************************************************************************************************/
	DXVertexDeclaration::~DXVertexDeclaration()
	{
	}
	/**********************************************************************************************************/
	const VertexElement& DXVertexDeclaration::AddElement(unsigned short source, size_t offset, VertexElementType theType, VertexElementSemantic semantic, unsigned short index)
	{
		m_needUpdate = true;
		return VertexDeclaration::AddElement(source, offset, theType, semantic, index);
	}
	/**********************************************************************************************************/
	void DXVertexDeclaration::RemoveElement(unsigned short elem_index)
	{
		m_needUpdate = true;
		VertexDeclaration::RemoveElement(elem_index);
	}
	/**********************************************************************************************************/
	void DXVertexDeclaration::RemoveElement(const VertexElement* elem)
	{
		m_needUpdate = true;
		VertexDeclaration::RemoveElement(elem);
	}
	/**********************************************************************************************************/
	void DXVertexDeclaration::RemoveAllElements(void)
	{
		m_needUpdate = true;
		VertexDeclaration::RemoveAllElements();
	}
	/**********************************************************************************************************/
	void DXVertexDeclaration::UpdateOffsets()
	{
		m_needUpdate = true;
		VertexDeclaration::UpdateOffsets();
	}
	/**********************************************************************************************************/
	IDirect3DVertexDeclaration9* DXVertexDeclaration::GetVertexDeclaration()
	{
		if(m_needUpdate)
		{
			// Create D3D elements
			RefPtr<D3DVERTEXELEMENT9, NoWeakPtrExtension, ArrayDelete> d3delems (new D3DVERTEXELEMENT9[m_elementList.size() + 1]);

			VertexElementList::const_iterator i, iend;
			unsigned int idx;
			iend = m_elementList.end();
			for (idx = 0, i = m_elementList.begin(); i != iend; ++i, ++idx)
			{
				d3delems.GetPointer()[idx].Method = D3DDECLMETHOD_DEFAULT;
				d3delems.GetPointer()[idx].Offset = static_cast<WORD>(i->GetOffset());
				d3delems.GetPointer()[idx].Stream = static_cast<WORD>(i->GetSource());
				d3delems.GetPointer()[idx].Type = static_cast<BYTE>(DXMappings::Get(i->GetType()));
				d3delems.GetPointer()[idx].Usage = static_cast<BYTE>(DXMappings::Get(i->GetSemantic()));
				// NB force index if colours since D3D uses the same usage for
				// diffuse & specular
				if (i->GetSemantic() == VES_SPECULAR)
				{
					d3delems.GetPointer()[idx].UsageIndex = 1;
				}
				else if (i->GetSemantic() == VES_DIFFUSE)
				{
					d3delems.GetPointer()[idx].UsageIndex = 0;
				}
				else
				{
					d3delems.GetPointer()[idx].UsageIndex = static_cast<BYTE>(i->GetIndex());
				}
			}
			// Add terminator
			d3delems.GetPointer()[idx].Stream = 0xff;
			d3delems.GetPointer()[idx].Offset = 0;
			d3delems.GetPointer()[idx].Type = D3DDECLTYPE_UNUSED;
			d3delems.GetPointer()[idx].Method = 0;
			d3delems.GetPointer()[idx].Usage = 0;
			d3delems.GetPointer()[idx].UsageIndex = 0;

			IDirect3DVertexDeclaration9* declaration = 0;


			if(FAILED(m_renderSystem->GetDirect3DGlobals()->d3dDevice->CreateVertexDeclaration(d3delems.GetPointer(), &declaration)))
				throw std::logic_error("DirectX can't create VertexDeclaration");

			m_vertexDeclaration = ComPtr<IDirect3DVertexDeclaration9>(declaration);
			m_needUpdate = false;

		}
		return m_vertexDeclaration.GetPointer();
	}
	/**********************************************************************************************************/
}
